%skeleton "lalr1.cc" /* -*- C++ -*- */
%defines
%define parser_class_name "MAliceParser"

%locations

%initial-action {
	// @$.begin.filename = @$.end.filename = &driver.file;
};


%code requires {

class MAliceDriver;
#include <MAliceCompiler/Ast/Ast.h>
#include <MAliceCompiler/Ast/ListAst.h>
#include <MAliceCompiler/Ast/ExpressionAst.h>

#ifdef NDEBUG
# define YYDEBUG (0)
#else
# define YYDEBUG (1)
#endif

}

%{

#include <MAliceCompiler/MAliceDriver.hpp>
#define yylex driver.getScanner()->scan


#include <MAliceCompiler/Ast/Ast.h>
#include <MAliceCompiler/Ast/ErrorAst.h>
#include <MAliceCompiler/Ast/ExpressionAst.h>
#include <MAliceCompiler/Ast/IntegerLiteralAst.h>
#include <MAliceCompiler/Ast/CharacterLiteralAst.h>
#include <MAliceCompiler/Ast/BinaryOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryAddOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryMulOperatorAst.h>
#include <MAliceCompiler/Ast/BinarySubOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryDivOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryModOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryAndOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryXorOperatorAst.h>
#include <MAliceCompiler/Ast/BinaryOrOperatorAst.h>
#include <MAliceCompiler/Ast/AssignmentOperatorAst.h>

#include <MAliceCompiler/Ast/UnaryAteOperatorAst.h>
#include <MAliceCompiler/Ast/UnaryDrankOperatorAst.h>
#include <MAliceCompiler/Ast/UnaryNegOperatorAst.h>
#include <MAliceCompiler/Ast/UnaryNotOperatorAst.h>
#include <MAliceCompiler/Ast/FloatLiteralAst.h>

#include <MAliceCompiler/Ast/ReturnExpressionAst.h>
#include <MAliceCompiler/Ast/VariableDeclAst.h>
#include <MAliceCompiler/Ast/VariableAst.h>
#include <MAliceCompiler/Ast/TypeAst.h>

using namespace MAlice;

%}

/* 
%lex-param   { MAliceDriver& driver } 
*/

%parse-param { MAliceDriver& driver }

%token     END              0 "End Of Line"
%token <s> id                 "id"
%token <b> bool_literal       "bool"
%token <c> char_literal       "char"
%token <i> int_literal        "int"
%token <f> float_literal      "float"
%token <s> string_literal     "string"

%token <i> shift_left         "<<"
%token <i> shift_right        ">>"

%token <i> less_than_equal    "<="
%token <i> greater_than_equal ">="
%token <i> equal              "=="
%token <i> not_equal          "!="

%token <s> kw_a      "a"
%token <s> kw_and    "and"
%token <s> kw_alice  "Alice"
%token <s> kw_became "became"
%token <s> kw_found  "found"
%token <s> kw_was    "was"
%token <s> kw_but    "but"
%token <s> kw_too    "too"
%token <s> kw_ate    "ate"
%token <s> kw_drank  "drank"

%union
{
	int                    i;
	double                 d;
	char                   c;
	bool                   b;
	string*                s;
	MAlice::Ast*           ast;
	MAlice::ExpressionAst* expr;
	MAlice::ListAst*       lists;
};

%type <ast>  type_id
%type <expr> literal
%type <expr> primary_expr
%type <expr> postfix_expr
%type <expr> unary_expr
%type <expr> cast_expr
%type <expr> multiplicative_expr
%type <expr> additive_expr		
%type <expr> shift_expr
%type <expr> relational_expr
%type <expr> equality_expr
%type <expr> and_expr
%type <expr> xor_expr
%type <expr> or_expr
%type <expr> assignment_expr

%type <expr> expr
%type <lists>  expr_list

%type <expr>  decl

%type <lists>  stmt_seq
%type <ast>  stmt




%destructor { } <*>

/* 
%destructor { delete $<ast>$;  } <type_id>
%destructor { delete $<ast>$;  } <literal>
%destructor { delete $<ast>$;  } <primary_expr>
%destructor { delete $<ast>$;  } <postfix_expr>
%destructor { delete $<ast>$;  } <unary_expr>
%destructor { delete $<ast>$;  } <cast_expr>
%destructor { delete $<ast>$;  } <multiplicative_expr>
%destructor { delete $<ast>$;  } <additive_expr>
%destructor { delete $<ast>$;  } <shift_expr>
%destructor { delete $<ast>$;  } <relational_expr>
%destructor { delete $<ast>$;  } <equality_expr>
%destructor { delete $<ast>$;  } <and_expr>
%destructor { delete $<ast>$;  } <xor_expr>
%destructor { delete $<ast>$;  } <or_expr>
%destructor { delete $<ast>$;  } <assignment_expr>
%destructor { delete $<expr>$; } <expr>
%destructor { delete $<ast>$;  } <stmt_seq>
%destructor { delete $<ast>$;  } <stmt>
*/

%left '*' '/' '%' '&' '^' '|' 

%%

%start stmt_seq;

literal
: "bool" {
	$$ = new ErrorAst("NotImplemented: bool_literal");
}
| "int" {
	 $$ = new IntegerLiteralAst($<i>1);
}
| "char" {
	 $$ = new CharacterLiteralAst($<c>1);
}
| "float" {
	 $$ = new FloatLiteralAst($<d>1);
}
| "string" {
	$$ = new ErrorAst("NotImplemented: string_literal");
}
;

type_id
: id {
		$$ = new TypeAst(*($1));
}
;

primary_expr
: literal {
	$$ = $1;
}
| '(' expr ')' {
	$$ = $2;
} 
| id {
	$$ = new VariableAst(*($1));
}
;

postfix_expr
: primary_expr {
	$$ = $1;
}
| postfix_expr "ate" {
	$$ = new UnaryAteOperatorAst($1);
}
| postfix_expr "drank" {
	$$ = new UnaryDrankOperatorAst($1);
}
;

unary_expr
: postfix_expr {
	$$ = $1;
}
| '-' cast_expr {
	$$ = new UnaryNegOperatorAst($2);
}
| '+' cast_expr {
	$$ = $2;
}
| '~' cast_expr {
	$$ = new UnaryNotOperatorAst($2);
}
;

cast_expr
: unary_expr {
	$$ = $1;
}
| '(' type_id ')' cast_expr {
	$$ = new ErrorAst("NotImplemented");
}
;

multiplicative_expr
: cast_expr {
	$$ = $1;
}
| multiplicative_expr '*' cast_expr {
	$$ = new BinaryMulOperatorAst($1, $3);
}
| multiplicative_expr '/' cast_expr {
	$$ = new BinaryDivOperatorAst($1, $3);
}
| multiplicative_expr '%' cast_expr {
	$$ = new BinaryModOperatorAst($1, $3);
}
;

additive_expr
: multiplicative_expr {
	$$ = $1;
}
| additive_expr '+' multiplicative_expr  {
	$$ = new BinaryAddOperatorAst($1, $3);
}
| additive_expr '-' multiplicative_expr {
	$$ = new BinarySubOperatorAst($1, $3);
}
;

shift_expr
: additive_expr {
	$$ = $1;
}
| shift_expr "<<" additive_expr {
	$$ = new ErrorAst("NotImplemented");
}
| shift_expr ">>" additive_expr {
	$$ = new ErrorAst("NotImplemented");
}
;

relational_expr
: shift_expr {
	$$ = $1;
}
| relational_expr '<'  shift_expr {
	$$ = new ErrorAst("NotImplemented");
}
| relational_expr '>'  shift_expr {
	$$ = new ErrorAst("NotImplemented");
}
| relational_expr "<=" shift_expr {
	$$ = new ErrorAst("NotImplemented");
}
| relational_expr ">=" shift_expr {
	$$ = new ErrorAst("NotImplemented");
}
;

equality_expr
: relational_expr {
	$$ = $1;
}
| equality_expr "==" relational_expr {
	$$ = new ErrorAst("NotImplemented");
}
| equality_expr "!=" relational_expr {
	$$ = new ErrorAst("NotImplemented");
}
;

and_expr
: equality_expr {
	$$ = $1;
}
| and_expr '&' equality_expr {
	$$ = new BinaryAndOperatorAst($1, $3);
}
;

xor_expr
: and_expr {
	$$ = $1;
}
| xor_expr '^' and_expr {
	$$ = new BinaryXorOperatorAst($1, $3);
}
;

or_expr
: xor_expr {
	$$ = $1;
}
| or_expr '|' xor_expr {
	$$ = new BinaryOrOperatorAst($1, $3);
}
;

assignment_expr
: id "became" or_expr {
	$$ = new AssignmentOperatorAst(new VariableAst(*$1), $3);
}
;

decl
: id "was" "a" type_id {
	$$ = new VariableDeclAst(*$1, (TypeAst*)$4);
}
| id "was" "a" type_id "too" {
	$$ = new VariableDeclAst(*$1, (TypeAst*)$4);
}
;

expr
:	decl {
	$$ = $1;
}
| assignment_expr {
	$$ = $1;
}
| "Alice" "found" or_expr {
	$$ = new ReturnExpressionAst($3);
}
;

expr_list
: expr {
	$$ = new ListAst($1);
}
| expr_list expr_list_sep expr {
	$$ = $1->adopt($3);
}
;

expr_list_sep
: "and" {}
| "but" {}
| ','   {}
;

stmt
: expr_list {
	$$ = $1;
}
;

stmt_term
: '.'  {}
| ','  {}
;

stmt_seq
: stmt {
	driver.put( $$ = new ListAst($1) );
}
| stmt_seq stmt_term stmt {
	driver.put( $$ = $1->adopt($3) );
}
;


%%

void yy::MAliceParser::error(yy::location const& loc, std::string const& msg)
{
	std::cerr << loc << ":" << msg << std::endl;
}


